﻿using System;
using System.Reflection;
using System.IO;
using System.Xml;
using XamlLocalizer.Services;

namespace XamlLocalizer.Parsing
{
    public class BindingResourceWrapperReplacement : IReplacementStrategy
    {
        private const string WpfDefaultNamespace = "http://schemas.microsoft.com/winfx/2006/xaml/presentation";
        private const string WpfXNamespace = "http://schemas.microsoft.com/winfx/2006/xaml";

        private readonly IResourceHandler resourceHandler;

        public BindingResourceWrapperReplacement(IResourceHandler resourceHandler)
        {
            this.resourceHandler = resourceHandler;
        }

        public string Id { get { return "BindResWrp"; } }

        public string Name { get { return "Binding to ResourcesWrapper"; } }

        public override string ToString()
        {
            return Name;
        }

        public bool ExtractRootElementAttributesIntoElements { get { return true; } }

        private static string GetFullKey(ResourceKeyDesc keyDesc)
        {
            return String.Format("{0}.{1}",
                keyDesc.ResourceFile, keyDesc.ItemKey);
        }

        public string GetAttributeReplacementValue(ResourceKeyDesc keyDesc)
        {
            return String.Format("{{Binding Path={0}, Source={{StaticResource ResourcesWrapper}}}}",
                GetFullKey(keyDesc));
        }

        public XmlElement CreateReplacementElement(XmlDocument ownerDoc, ResourceKeyDesc keyDesc)
        {
            XmlElement newElem = ownerDoc.CreateElement("Binding", WpfDefaultNamespace);

            newElem.SetAttribute("Path", GetFullKey(keyDesc));
            newElem.SetAttribute("Source", "{StaticResource ResourcesWrapper}");

            return newElem;
        }

        public void PrepareReplacement(XamlExtractor xamlExtractor, string resourcesNamespace, string resourceClass)
        {
            string xmlNs = "clr-namespace:" + resourcesNamespace;
            xamlExtractor.AddNamespace(XamlExtractor.XamlParseInfo.ReplaceSettings.LocExtPrefix, xmlNs);

            GenerateResourceWrapperClass(xamlExtractor, resourcesNamespace, resourceClass);

            GenerateResourceWrapperElement(xamlExtractor, xmlNs);
        }

        private void GenerateResourceWrapperClass(XamlExtractor xamlExtractor, string resourcesNamespace, string resourceClass)
        {
            string propsFolder = resourceHandler.GetResourcesFolder();
            string fileName = Path.Combine(propsFolder, String.Format("ResourcesWrapper.{0}.cs", resourceClass));
            if (!File.Exists(fileName))
            {
                string homedir = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
                string tplFileName = Path.Combine(homedir, "ResourcesWrapper.tpl");
                string tpl = File.ReadAllText(tplFileName);
                string classSource = tpl.Replace("{Namespace}", resourcesNamespace).Replace("{ResourceClass}", resourceClass);
                File.WriteAllText(fileName, classSource);

                resourceHandler.AddCSharpFile(fileName);
            }
        }

        private static void GenerateResourceWrapperElement(XamlExtractor xamlExtractor, string xmlNs)
        {
            XmlElement rootElem = xamlExtractor.Document.DocumentElement;
            if (rootElem == null) return;

            XmlElement parElem;
            bool isResourceDictionary = (rootElem.LocalName == "ResourceDictionary");
            if (isResourceDictionary)
            {
                parElem = rootElem;
            }
            else
            {
                string resElemName = rootElem.LocalName + ".Resources";
                parElem = rootElem[resElemName];
                if (parElem == null)
                {
                    parElem = xamlExtractor.Document.CreateElement(resElemName, WpfDefaultNamespace);
                    rootElem.InsertBefore(parElem, rootElem.FirstChild);

                    var wht = xamlExtractor.Document.CreateWhitespace("\n    ");
                    rootElem.InsertBefore(wht, parElem);
                }
            }

            var resWrapElem = parElem["ResourcesWrapper", xmlNs];
            if (resWrapElem == null)
            {
                resWrapElem =
                    xamlExtractor.Document.CreateElement(XamlExtractor.XamlParseInfo.ReplaceSettings.LocExtPrefix,
                                                         "ResourcesWrapper", xmlNs);
                resWrapElem.SetAttribute("Key", WpfXNamespace, "ResourcesWrapper");

                parElem.InsertBefore(resWrapElem, parElem.FirstChild);

                var wht = xamlExtractor.Document.CreateWhitespace(isResourceDictionary ? "\n    " : "\n        ");
                rootElem.InsertBefore(wht, parElem);
            }
        }
    }
}
